package com.ipan.jfinal.tdo.bigFile;

import java.io.File;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.ipan.jfinal.tdo.OutputKits;
import com.ipan.jfinal.tdo.config.Tpl;
import com.ipan.jfinal.tdo.exception.TransformException;
import com.ipan.jfinal.tdo.out.TdoValidator;
import com.ipan.jfinal.tdo.transform.Transducer;
import com.ipan.kits.base.ExceptionUtil;
import com.jfinal.plugin.activerecord.Model;

/**
 * 
 * 读文件监听器（带模板）
 * 
 * 1）实行严格的转换标准；
 * 2）逐行解析，逐行写入；
 * 3）中途失败，会终止转换，整个转换就失败；
 * 
 * @author iPan
 * @date 2022-01-25
 */
public class ReadBigFileToDbListener extends AnalysisEventListener<Map<Integer, String>> {
	
	protected Logger logger = LoggerFactory.getLogger(getClass());
	protected Tpl tpl = null;
	protected Class beanClass = null; // JavaBean类型
	protected Integer rowIndex = -1; // 从0开始
	protected Integer cellIndex = -1; // 从0开始
	/** 数据格式校验 */
	protected TdoValidator validator = TdoValidator.DEFAULT_VALIDATOR;
	protected long startTime = System.currentTimeMillis();
	
	public ReadBigFileToDbListener(File fout, Tpl tpl, Class beanClass) {
		this.tpl = tpl;
		this.beanClass = beanClass;
	}
	
	public Class getBeanClass() {
		return beanClass;
	}

	public void setBeanClass(Class beanClass) {
		this.beanClass = beanClass;
	}

	public TdoValidator getValidator() {
		return validator;
	}

	public void setValidator(TdoValidator validator) {
		this.validator = validator;
	}

	@Override
	public void invoke(Map<Integer, String> data, AnalysisContext context) {
		// 转换行数据
		try {
			this.rowIndex = context.readRowHolder().getRowIndex(); // 从0计数
			int cfgIndex = this.tpl.getIndex(); // 从0计数
			if (this.rowIndex <= cfgIndex) {
				return ;
			}
			//过滤空行
			if (OutputKits.isBlankLine(data.values())) {
				return ;
			}
			// 校验行
			String errMsg = validator.validate(data, tpl.getKeyType());
			if (StringUtils.isNotBlank(errMsg)) {
				logger.info("文件校验不合格，原因：{}。", errMsg);
				throw new java.lang.IllegalArgumentException(errMsg);
			}
			// 转换行
			Integer rowIndex = context.readRowHolder().getRowIndex(); // 当前行
			Map<Integer, String> retRow = Transducer.me().transform(data, rowIndex, this.tpl);
			// 转JavaBean
			Model bean = (Model) OutputKits.rowToJavaBean(tpl, retRow, cfgIndex+1, beanClass);
			// 保存记录
			doSave(bean);
		} catch(Exception e) {
			ExceptionUtil.unchecked(e);
		}
	}
	
	/**
	 * 保存记录（若需要对插入与更新做区分，需重写该方法）
	 */
	public void doSave(Model bean) {
		if (bean != null) bean.save();
	}

	@Override
	public void doAfterAllAnalysed(AnalysisContext context) {
		long second = (System.currentTimeMillis() - startTime) / 1000; // 耗时：秒
		logger.info("转换文件{}完成，耗时{}秒。", context.readWorkbookHolder().getFile().getName(), second);
	}
	
	@Override
	public void onException(Exception exception, AnalysisContext context) throws Exception {
		// 记录错误位置
		logger.error("转换文件{}第{}行异常", 
				context.readWorkbookHolder().getFile().getName(), context.readRowHolder().getRowIndex());
		logger.error("文件转换异常", exception);
		// 抛出转换异常
		if (exception instanceof TransformException) {
			throw exception;
		} else {
			TransformException transformExce = new TransformException(exception.getMessage(), exception);
			transformExce.setRowIndex(rowIndex);
			transformExce.setCellIndex(cellIndex);
			throw transformExce;
		}
	}
	
	@Override
	public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
		this.rowIndex = context.readRowHolder().getRowIndex();
		int currentHeadRowNumber = context.readSheetHolder().getHeadRowNumber();
		// 多行标题的情况，前面几行都会被回调；
		if (this.rowIndex + 1 == currentHeadRowNumber) {
			logger.info("转换文件：{}，{}行。", context.readWorkbookHolder().getFile().getName(), this.rowIndex);
			logger.info("解析标题：{}", headMap);
		}
	}

}
